/*
 * Copyright (C) 2017 Hisilicon Limited.
 *
 * This program is free software; you can redistribute it and /or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version
 */

#ifndef __DEVDRV_ADMIN_MSG_H_
#define __DEVDRV_ADMIN_MSG_H_

#include "nvme_drv.h"
#include "devdrv_interface.h"

#define DEVDRV_P2P_SURPORT_MAX_DEVICE 8

enum msg_queue_type {
    TRANSPARENT_MSG_QUEUE = 0,
    NON_TRANSPARENT_MSG_QUEUE,
    MSG_QUEUE_TYPE_MAX
};

#define DEVDRV_MSG_MEM_BASE 0
#define DEVDRV_MAX_QUEUE_SIZE 0x10000 /* 64KB */
#define DEVDRV_PCIE_RESERVE_MEM_SIZE (9 * 1024 * 1024)
#define DEVDRV_MSG_QUEUE_MEM_SIZE DEVDRV_RESERVE_MEM_MSG_SIZE /* 8MB */
#define DEVDRV_MAX_QUEUE_CNT ((DEVDRV_MSG_QUEUE_MEM_SIZE) / (DEVDRV_MAX_QUEUE_SIZE) / 2)


/* The command channel uses a memory synchronous call */
#define DEVDRV_ADMIN_MSG_QUEUE_DEPTH 1
#define DEVDRV_ADMIN_MSG_QUEUE_BD_SIZE 128

#define DEVDRV_MSG_TIMEOUT 3000000             /* 3s */
#define DEVDRV_MSG_D2H_TIMEOUT 30000000        /* 30s */
#define DEVDRV_MSG_IRQ_TIMEOUT 1000000         /* 1s */
#define DEVDRV_MSG_WAIT_DMA_FINISH_TIMEOUT 100 /* 100ms */
#define DEVDRV_MSG_SCHEDULE_MAX_TIME 1000      /* 1000s */
#define DEVDRV_MSG_TIME_OVERFLOW 5000          /* 5s */


#define DEVDRV_MSG_WAIT_MIN_TIME 1 /* 1us */
#define DEVDRV_MSG_WAIT_MAX_TIME 2 /* 2us */

#define DEVDRV_SHR_PARA_ADDR_OFFSET 0x400
#define DEVDRV_SHR_PARA_ADDR_SIZE 0x400

#define DEVDRV_P2P_MSG_SIZE 0x400 /* msg 1KB */
#define DEVDRV_P2P_SEND_MSG_ADDR_OFFSET (0)
#define DEVDRV_P2P_SEND_MSG_ADDR_SIZE (DEVDRV_P2P_MSG_SIZE * DEVDRV_P2P_SURPORT_MAX_DEVICE)
#define DEVDRV_P2P_RECV_MSG_ADDR_OFFSET (DEVDRV_P2P_SEND_MSG_ADDR_OFFSET + DEVDRV_P2P_SEND_MSG_ADDR_SIZE)
#define DEVDRV_P2P_RECV_MSG_ADDR_SIZE (DEVDRV_P2P_MSG_SIZE * DEVDRV_P2P_SURPORT_MAX_DEVICE)
#define DEVDRV_P2P_MSG_ADDR_OFFSET (DEVDRV_SHR_PARA_ADDR_OFFSET + DEVDRV_SHR_PARA_ADDR_SIZE)
#define DEVDRV_P2P_MSG_ADDR_TOTAL_SIZE (DEVDRV_P2P_SEND_MSG_ADDR_SIZE + DEVDRV_P2P_RECV_MSG_ADDR_SIZE)

/* cmd opreation code, first 8 bits is mudule name, later 8 bits is op type */
enum devdrv_admin_msg_opcode {
    /* msg chan */
    DEVDRV_CREATE_MSG_QUEUE,
    DEVDRV_FREE_MSG_QUEUE,
    DEVDRV_NOTIFY_DMA_ERR_IRQ,
    DEVDRV_GET_GELNERAL_INTERRUPT_DB_INFO,
    DEVDRV_NOTIFY_DEV_ONLINE,
    DEVDRV_ADMIN_MSG_MAX
};

#define DEVDRV_MSG_CMD_BEGIN 1
#define DEVDRV_MSG_CMD_FINISH_SUCCESS 2
#define DEVDRV_MSG_CMD_FINISH_FAILED 3
#define DEVDRV_MSG_CMD_INVALID_PARA 4
#define DEVDRV_MSG_CMD_NULL_PROCESS_CB 5
#define DEVDRV_MSG_CMD_IRQ_BEGIN 0x69727173 /* irqs */

struct devdrv_create_queue_command {
    u32 msg_type;   /* enum devdrv_msg_client_type */
    u32 queue_type; /* enum msg_queue_type */
    u32 queue_id;
    u64 sq_dma_base_host;
    u64 cq_dma_base_host;
    u32 sq_desc_size;
    u32 cq_desc_size;
    u16 sq_depth;
    u16 cq_depth;
    s32 irq_tx_finish_notify;
    s32 irq_rx_msg_notify;
};

struct devdrv_free_queue_cmd {
    u32 queue_id;
};

struct devdrv_notify_dma_err_irq_cmd {
    u32 dma_chan_id;
    u32 err_irq;
};

struct devdrv_general_interrupt_db_info {
    u32 db_start;
    u32 db_num;
};

struct devdrv_notify_dev_online_cmd {
    u32 devid;
    u32 status;
};

/* DMA single node read and write command */
struct devdrv_dma_single_node_command {
    struct devdrv_dma_node dma_node;
};

/* DMA chained read and write command */
struct devdrv_dma_chain_command {
    u64 dma_node_base;
    u32 node_cnt;
};

struct devdrv_admin_msg_command {
    u32 opcode;
    u32 status;
    char data[0];
};

struct devdrv_admin_msg_reply {
    u32 len; // contain 'len' own occupied space
    char data[0];
};

#define DEVDRV_ADMIN_MSG_HEAD_LEN sizeof(struct devdrv_admin_msg_command)
#define DEVDRV_ADMIN_MSG_DATA_LEN (DEVDRV_ADMIN_MSG_QUEUE_BD_SIZE - DEVDRV_ADMIN_MSG_HEAD_LEN)


struct devdrv_non_trans_msg_desc {
    u32 in_data_len;  /* input real length */
    u32 out_data_len; /* output max length */
    u32 real_out_len; /* output real length */
    u32 msg_type;     /* enum devdrv_common_msg_type */
    u32 status;       /* DEVDRV_MSG_CMD_* */
    char data[0];
};

#define DEVDRV_NON_TRANS_MSG_HEAD_LEN sizeof(struct devdrv_non_trans_msg_desc)

struct devdrv_shr_para {
    int load_flag;         /* D2H: device bios notice host to load device os via pcie. 0: no, 1 yes */
    int load_wait_time;    /* D2H: device bios notice host how long to wait device os start, unit second */
    int node_id;           /* D2H: device bios notice host: cloud ai server has total 8P, one node has 4p, which node */
    int dev_id;            /* D2H: device bios notice host: cloud ai server, index in one node(4P 0-3); others 0 */
    int board_type;        /* D2H: device bios notice host: cloud pcie card, ai server, evb */
    int chip_type;         /* D2H: mini cloud */
    int platform_type;     /* D2H: esl, emu, fpga, asic */
    int dev_num;           /* D2H: cloud ai server, total dev num 4; others 1  */
    int host_dev_id;       /* H2D: the dev id in host side */
    int half_probe_flag;   /* H2D: host notice device has receive interrupt begin half probe. 0: no, 1 yes */
    u32 admin_msg_status;  /* host set begin, device irq set irq_begin, host continue */
    u64 host_mem_bar_base; /* H2D: mem bar 4 base addr */
    u64 host_io_bar_base;  /* H2D: io bar 2 base addr */
    u64 tx_atu_base_addr1; /* D2H: cloud only, high 256GB address space */
    u64 tx_atu_base_size1; /* D2H: cloud only, high 256GB space size */
    u64 tx_atu_base_addr2; /* D2H: cloud only, low 128MB address space */
    u64 tx_atu_base_size2; /* D2H: cloud only, low 128MB space size */
    u64 p2p_msg_base_addr[DEVDRV_P2P_SURPORT_MAX_DEVICE]; /* H2D: cloud only, p2p msg base for dma */
    u64 p2p_db_base_addr[DEVDRV_P2P_SURPORT_MAX_DEVICE];  /* H2D: cloud only, p2p doorbell base for dma */
    volatile u64 heartbeat_count;                         /* devmng set in device, get in host */
    volatile u64 runtime_runningplat; /* runtime running in device(0xdece) or host(0xa5a5), runtime stop:0x0 */
    volatile u32 ts_host_irq_base;    /* H2D: host notice device: host type for ts irq base */
    volatile u32 ts_host_irq_mode;    /* H2D: host notice device: host type for ts irq mode */
};

#endif
